package com.imooc.bilibili.service;

import com.alibaba.fastjson.JSONObject;
import com.imooc.bilibili.dao.UserDao;
import com.imooc.bilibili.domain.PageResult;
import com.imooc.bilibili.domain.RefreshToken;
import com.imooc.bilibili.domain.User;
import com.imooc.bilibili.domain.UserInfo;
import com.imooc.bilibili.constant.UserConstant;
import com.imooc.bilibili.exception.ConditionException;
import com.imooc.bilibili.util.MD5Util;
import com.imooc.bilibili.util.RSAUtil;
import com.imooc.bilibili.util.TokenUtil;
import com.mysql.cj.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
@Slf4j
public class UserService {

    @Autowired
    private UserDao userDao;

    @Autowired
    private UserAuthService userAuthService;

    @Autowired
    private ElasticSearchService elasticSearchService;

    /**
     * 用户注册
     * @param user
     * @return
     */
    public void addUser(User user) {
        String phone = user.getPhone();
        if(StringUtils.isNullOrEmpty(phone)){
            throw new ConditionException("手机号不能为空!");
        }
        // 通过手机号查询此用户是否已经存在
        User userByPhone = getUserByPhone(phone);
        if(userByPhone != null){
            throw new ConditionException("该手机号已经注册!");
        }
        String password = user.getPassword();
        String decryptPassword = null;
        try {
         decryptPassword = RSAUtil.decrypt(password);
        } catch (Exception e) {
            throw new ConditionException("密码解密失败!");
        }
        // 生成用户的日期盐值
        Date now = new Date();
        String salt = String.valueOf(now.getTime());
        // 对密码重新MD5加密
        String md5Password = MD5Util.sign(decryptPassword, salt, "UTF-8");
        user.setPassword(md5Password);
        user.setSalt(salt);
        user.setCreateTime(now);
        // 添加新用户
        userDao.addUser(user);
        // 添加用户信息
        UserInfo userInfo = new UserInfo();
        userInfo.setUserId(user.getId());
        userInfo.setNick(UserConstant.DEFAULT_NICK);
        userInfo.setBirth(UserConstant.DEFAULT_BIRTH);
        userInfo.setGender(UserConstant.GENDER_MALE);
        userInfo.setCreateTime(now);
        userDao.addUserInfo(userInfo);
        elasticSearchService.addUserInfo(userInfo);

        // 添加用户默认权限角色
        userAuthService.addUserDefaultRole(user.getId());
    }

    /**
     * 通过手机号查询用户
     * @return
     */
    private User getUserByPhone(String phone) {
       return userDao.getUserByPhone(phone);
    }

    /**
     * 用户登录
     * @param user
     * @return
     */
    public String login(User user) throws Exception {
        String phone = user.getPhone() == null ? "" : user.getPhone();
        String email = user.getEmail() == null ? "" : user.getEmail();
        if(StringUtils.isNullOrEmpty(phone) && StringUtils.isNullOrEmpty(email)){
            throw new ConditionException("参数异常！");
        }
        User dbUser = this.getUserByPhoneOrEmail(phone,email);

        if(dbUser == null){
            throw new ConditionException("该用户不存在!");
        }
        String password = user.getPassword();
        String decryptPassword = null;
        try {
             decryptPassword = RSAUtil.decrypt(password);
        } catch (Exception e) {
            throw new ConditionException("密码解密失败!");
        }
        String salt = dbUser.getSalt();
        String md5Password = MD5Util.sign(decryptPassword, salt, "UTF-8");
        if (!md5Password.equals(dbUser.getPassword())) {
            throw new ConditionException("用户名或密码错误!");
        }
        String token = TokenUtil.generateToken(dbUser.getId());
        return token;
    }


    /**
     * 通过手机号或邮箱查询用户
     * @param phone
     * @param email
     * @return
     */
    private User getUserByPhoneOrEmail(String phone, String email) {
        return userDao.getUserByPhoneOrEmail(phone,email);
    }

    /**
     * 通过id查询用户
     * @param userId
     * @return
     */
    public User getUserById(Long userId) {
        User user = userDao.getUserById(userId);
        return user;
    }

    /**
     * 根据userId查询用户信息
     * @param userId
     * @return
     */
    public User getUserInfo(Long userId){
        User user = userDao.getUserById(userId);
        UserInfo userInfo = userDao.getUserInfoByUserId(userId);
        user.setUserInfo(userInfo);
        return user;
    }

    /**
     * phone、email以及password三个字段的更新功能
     * @param user
     */
    public void updateUsers(User user) {
        // 通过id对user信息进行修改
        Long userId = user.getId();
        User dbUser = this.getUserById(userId);
        if (dbUser == null) {
            throw new ConditionException("该用户不存在！");
        }
        String password = user.getPassword();
        try {
            if (!StringUtils.isNullOrEmpty(user.getPassword())) {
                String rsaPassword = RSAUtil.decrypt(password);
                String md5Password = MD5Util.sign(rsaPassword, user.getSalt(), "UTF-8");
                user.setPassword(md5Password);
            }
        } catch (Exception e) {
            throw new ConditionException("密码解密失败！");
        }
        user.setUpdateTime(new Date());
        userDao.updateUsers(user);
    }

    /**
     * 通过userId更新用户信息
     * @param userInfo
     * @return
     */
    public void updateUserInfos(UserInfo userInfo) {
        userInfo.setUpdateTime(new Date());
        userDao.updateUserInfos(userInfo);
    }

    /**
     * 通过set集合中用户id查询用户详细信息
     * @param followingIdSet
     * @return
     */
    public List<UserInfo> getUserInfoByUserIds(Set<Integer> followingIdSet) {
        return userDao.getUserInfoByUserIds(followingIdSet);
    }

    /**
     * 获取用户信息分页
     * @param params
     * @return
     */
    public PageResult<UserInfo> pageListUserInfos(JSONObject params) {
        Integer no = params.getInteger("no");
        Integer size = params.getInteger("size");
        params.put("start",(no-1)*size);
        Integer count = userDao.pageCountUserInfos(params);
        List<UserInfo> userInfoList = new ArrayList<>();
        if(count > 0){
            userInfoList = userDao.pageListUserInfos(params);
        }
        return new PageResult<>(count,userInfoList);
    }

    /**
     * 基于双token实现登录
     * @param user
     * @return
     */
    public Map<String, Object> loginForDts(User user) throws Exception {
        String phone = user.getPhone() == null ? "" : user.getPhone();
        String email = user.getEmail() == null ? "" : user.getEmail();
        if(StringUtils.isNullOrEmpty(phone) && StringUtils.isNullOrEmpty(email)){
            throw new ConditionException("参数异常！");
        }
        User dbUser = this.getUserByPhoneOrEmail(phone,email);

        if(dbUser == null){
            throw new ConditionException("该用户不存在!");
        }
        String password = user.getPassword();
        String decryptPassword = null;
        try {
            decryptPassword = RSAUtil.decrypt(password);
        } catch (Exception e) {
            throw new ConditionException("密码解密失败!");
        }
        String salt = dbUser.getSalt();
        String md5Password = MD5Util.sign(decryptPassword, salt, "UTF-8");
        if (!md5Password.equals(dbUser.getPassword())) {
            throw new ConditionException("用户名或密码错误!");
        }

        Long userId = dbUser.getId();
        String accessToken = TokenUtil.generateToken(userId);
        String refreshToken = TokenUtil.generateRefreshToken(userId);
        // 保存refreshToken到数据库
        userDao.deleteRefreshToken(refreshToken,userId);
        userDao.addRefreshToken(refreshToken,userId,new Date());
        Map<String,Object> result = new HashMap<>();
        result.put("accessToken",accessToken);
        result.put("refreshToken",refreshToken);
        return result;
    }

    /**
     * 用户退出
     * @param refreshToken
     * @param userId
     */
    public void logout(String refreshToken, Long userId) {
        userDao.deleteRefreshToken(refreshToken, userId);
    }

    /**
     * 刷新accessToken
     * @param refreshToken
     * @return
     */
    public String refreshAccessToken(String refreshToken) throws Exception {
        RefreshToken refreshTokenDetail = userDao.getRefreshTokenDetail(refreshToken);
        if (refreshTokenDetail == null) {
            throw new ConditionException("555","token过期！");
        }
        // 验证refreshToken的合法性
        TokenUtil.verifyRefreshToken(refreshToken);
        Long userId = refreshTokenDetail.getUserId();
        String accessToken = TokenUtil.generateToken(userId);
        return accessToken;
    }

    /**
     * 通过用户id获取refreshToken
     * @param userId
     * @return
     */
    public String getRefreshTokenByUserId(Long userId) {
        return userDao.getRefreshTokenByUserId(userId);
    }
}
